package ast_generator;


import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class LexScanner {
	  HashMap characterClasses;
	  HashMap tokenMap;

	public LexScanner(){
		characterClasses=new HashMap();
		tokenMap = new HashMap();
	}
	/**
	 * creates the character classes and tokenMaps for the entire lex file. The character classes are stored in the tokenMap HashMap. The key for the map represents the name of the token, the alue is the regex expression.
	 * @param input string represents the name of the file we will use.
	 */
	public void generateCharacterClasses(String input)
	{
		boolean go= true;
		String strLine=new String();
		String regex=new String();
		try{
			  
			  FileInputStream fstream = new FileInputStream(input);
			  DataInputStream in = new DataInputStream(fstream);
			  BufferedReader br = new BufferedReader(new InputStreamReader(in));
			  //for every line that represents a character class
			  while (((strLine = br.readLine()) != null)&& go)   { 
			  strLine=processCharacterClasses(strLine);
			  if(strLine.equals(""))
			  {
				  go=false;// quit when out of character classes.
			  }
			  }
			  
			  
			  //System.out.println(strLine);
			  
			  
			  //Process the first line
			   if(strLine.charAt(0)=='$')
			   {
				   processToken(strLine);
			   }
			   while(((strLine = br.readLine()) != null)&&strLine.charAt(0)=='$')//keep up the
			   {
				   processToken(strLine); 
			   }
			   
			   in.close();
			   }
		catch (Exception e){
			  System.err.println("Error: " + e.getMessage());
		}
		
		
	}
	
	/**
	 * processes a line of a string for a token. The token is added
	 * @param strLine line beign processed for a token.
	 */
	private void processToken(String strLine) {
		
		String token="";
		String regex="";
		int space=strLine.indexOf(" ");
		int tab= strLine.indexOf("\t");
		if(((space<tab)&&space!=-1)||(space!=-1 && tab==-1))
		{
		token=strLine.substring(0,strLine.indexOf(" "));
		 regex= strLine.substring(strLine.indexOf(" "));
		}
		if((tab<space&&tab!=-1)||(tab!=-1&&space==-1))
		{
		token=strLine.substring(0,strLine.indexOf("\t"));
		 regex= strLine.substring(strLine.indexOf("\t"));
		}
		if(regex==""||token=="")
		{
			throw new RuntimeException();
		}
		tokenMap.put(token,regex);
		//System.out.println("Token "+ token);
		//System.out.println("Regex "+regex);
		
	}
	
	/**process string. if it is a character class, put it into Hashmap
	 * 
	 * @param strLine line we are processing into a character class
	 * @return String string is either an empty string if we recieve invalid material for the line, or it is just strLine
	 */
	private String processCharacterClasses(String strLine) {
		    String temp=strLine;
		    String key=new String("");
		    boolean in=false;
		    ArrayList<String> value=new ArrayList<String>();
		    ArrayList<String> set=new ArrayList<String>();
		    if(strLine.length()==0)//if the string starts with a space, assume we are done with generating character classes
			{
				return "";
			}
			if(strLine.charAt(0)==' ')//if the string starts with a space, assume we are done with generating character classes
			{
				return "";
			}
			else if(strLine.charAt(0)=='%')
			{
				return strLine;
			}
			else if(strLine.charAt(0)=='$') //if this generates a character class
			{
				int end=temp.indexOf('[');
				int space=temp.indexOf(' ');
				//grabs the key
				if(space<end)
				{
					key=temp.substring(0,space); 
				}
				else
				{
					key=temp.substring(0,end+1); 
				}
				//System.out.println(key);
				//temp now contains everything after the opening '['
				temp=temp.substring(end+1);
				
				if(temp.charAt(0)=='^')
				{
					in = true;
					temp=temp.substring(1);
				}
				boolean go=true;
				
				while(temp.length()>=1 && go)
				{
					char c=temp.charAt(0);
					if(c==92) //if the current character is a backslash
					{
						temp=temp.substring(1);
						set.add(Character.toString(temp.charAt(0)));
					}
					else if (c==']') //stop if we reach a ]
					{
						go=false;
					}
					else if(c=='-')//- operator
					{
						temp=temp.substring(1);
						 c=temp.charAt(0);
						if(c==92) //if the current character is a backslash, get next character
						{
							temp=temp.substring(1);
							value.add(Character.toString(temp.charAt(0)));
						}
						int startChar=(set.get(set.size()-1).charAt(0)+1);
						int endChar=c;
						while(startChar<endChar)//generate the arraylist containg characters from startChar to endChar
						{
							set.add(Character.toString((char)startChar));
							startChar++;
						}

					}
					else
					{
						set.add(Character.toString(temp.charAt(0)));
						temp=temp.substring(1);
					}
				}
					
					if(in)//if we are under ^ operator
					{
						temp=temp.substring(temp.indexOf("$"));
						//goal is for temp to contain the key of the s
						if(temp.indexOf(' ')!=-1)
						{
							temp=temp.substring(0,temp.lastIndexOf(' '));
							
						}
						else
						{
							temp=temp.substring(0,temp.length());
						}
						ArrayList<String> parentSet= (ArrayList<String>) characterClasses.get(temp);
						if(parentSet!=null)
						{
						for (String s : parentSet)//generate parent set, the set we will be excluding from
						{
							if(!set.contains(s))
							{
								value.add(s);
							}
						}
						}
						
					}
					else//take away from the parent set what you want excluded
					{
						for (String s : set)
						{
							if(!value.contains(s))
							value.add(s);
						}
					}
				}
				//System.out.println(value);
			    characterClasses.put(key, value);
			
		return strLine;//get rid of errors
	}
	/**
	 * accessor method
	 * @return characterClasses
	 */
	public HashMap getCharacterClasses() {
		// TODO Auto-generated method stub
		return characterClasses;
	}
	/**
	 * accessor method
	 * @return tokenMap
	 */
	public HashMap getTokenMap() {
		// TODO Auto-generated method stub
		return tokenMap;
	}
	
			
}

